﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using DslModeling=global::Microsoft.VisualStudio.Modeling;

namespace Salamanca.Sdml
{



    /// <summary>Type converter that provides a list of values to be displayed to select the <see cref="EntityAttribute.Type" /> of an <see cref="EntityAttribute" />.</summary>
    public class TypesProviderConverter:
        TypeConverter
    {

        /// <summary>Returns <c>true</c> to indicate that we return a list of values to choose from.</summary>
        public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
        {
            return true;
        }

        /// <summary>Returns <c>true</c> to indicate that the user has to select a value from the list.</summary>
        /// <returns><c>true</c>. If we returned <c>false</c>, the user would be able to either select a value from 
        /// the list or type in a value that is not in the list.</returns>
        public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
        {
            return true;
        }

        /// <summary>Returns a list of the values to display in the grid.</summary>
        /// <returns>A list of values the user can choose from.</returns>
        public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
        {
            // Try to get a store from the current context
            // "context.Instance"  returns the element(s) that are currently selected i.e. whose values are being
            // shown in the property grid. Note that the user could have selected multiple objects, in which case 
            // context.Instance will be an array.
            DslModeling.Store store=GetStore(context.Instance);

            return new StandardValuesCollection((ICollection)GetAllowedTypes(store));
        }

        /// <summary>Attempts to get to a store from the currently selected object(s) in the property grid.</summary>
        private DslModeling.Store GetStore(object gridSelection)
        {
            // We assume that "instance" will either be a single model element, or 
            // an array of model elements (if multiple items are selected).
            DslModeling.ModelElement currentElement=null;

            object[] objects=gridSelection as object[];
            if ((objects!=null) && (objects.Length>0))
                currentElement=objects[0] as DslModeling.ModelElement;
            else
                currentElement=gridSelection as DslModeling.ModelElement;

            return (currentElement==null) ? null : currentElement.Store;
        }

        /// <summary>Returns a list of all the valid types in the specified <paramref name="store" />.</summary>
        internal static IList<string> GetAllowedTypes(DslModeling.Store store)
        {
            if (store==null)
                return _AllowedTypes;

            List<string> ret=new List<string>(_AllowedTypes);

            // Add all enumerations names
            ret.AddRange(store.ElementDirectory.FindElements<DomainEnum>().Select<DomainEnum, string>(e => e.Name));
            ret.Sort();

            return ret;
        }

        private static string[] _AllowedTypes=new string[] { "bool", "DateTime", "double", "float", "Guid", "int", "long", "short", "string" };
    }



    /// <summary>Type converter that provides a list of values to be displayed to select the <see cref="DomainEnum.UnderlyingType" /> of a <see cref="DomainEnum" />.</summary>
    public class EnumTypesProviderConverter:
        TypeConverter
    {

        /// <summary>Returns <c>true</c> to indicate that we return a list of values to choose from.</summary>
        public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
        {
            return true;
        }

        /// <summary>Returns <c>true</c> to indicate that the user has to select a value from the list.</summary>
        /// <returns><c>true</c>. If we returned <c>false</c>, the user would be able to either select a value from 
        /// the list or type in a value that is not in the list.</returns>
        public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
        {
            return true;
        }

        /// <summary>Returns a list of the values to display in the grid.</summary>
        /// <returns>A list of values the user can choose from.</returns>
        public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
        {
            List<string> list=new List<string>(IntegralTypes);
            list.AddRange(_OtherTypes);
            list.Sort();

            return new StandardValuesCollection(list);
        }

        public static readonly string[] IntegralTypes=new string[] { "byte", "int", "long", "short" };

        private static string[] _OtherTypes=new string[] { "string" };
    }
}
